﻿using System;
using System.Linq;
using System.Net;
using System.Text;
using System.Threading.Tasks;
using System.Web;
using Altairis.FluffyCloud.Data;
using Altairis.FluffyCloud.Storage;

namespace Altairis.FluffyCloud.WebCore.Handlers {

    public class UserIconHandler : HttpTaskAsyncHandler {
        private const string GRAVATAR_URL = "http://www.gravatar.com/avatar/{0}?s={1}&d=identicon&r=x";

        public override async Task ProcessRequestAsync(HttpContext context) {
            var userName = context.Request.RequestContext.RouteData.Values["userName"] as string;
            var iconSize = int.Parse(context.Request.RequestContext.RouteData.Values["iconSize"] as string);

            // Try to get local icon
            var data = UserIcon.Download(userName, iconSize);
            if (data != null) {
                // We have local icon, which is always PNG
                context.Response.ContentType = "image/png";
            }
            else {
                // We don't have local icon, use Gravatar service
                var url = string.Format(GRAVATAR_URL, GetHashForUser(userName), iconSize);
                var wc = new WebClient();
                data = await wc.DownloadDataTaskAsync(url);
                context.Response.ContentType = wc.ResponseHeaders["Content-Type"];
            }

            // Send data to client
            await context.Response.OutputStream.WriteAsync(data, 0, data.Length);

            // Setup caching
            if (context.IsDebuggingEnabled) {
                // Disable caching in debug mode
                context.Response.Cache.SetCacheability(HttpCacheability.NoCache);
            }
            else {
                // Cache for next 5 minutes
                context.Response.Cache.SetCacheability(HttpCacheability.ServerAndPrivate);
                context.Response.Cache.SetExpires(DateTime.Now.AddMinutes(5));
                context.Response.Cache.SetValidUntilExpires(true);
                context.Response.Cache.VaryByParams.IgnoreParams = true;
            }
        }

        private static string ComputeMD5(string email) {
            if (email == null) throw new ArgumentNullException("email");
            if (string.IsNullOrWhiteSpace(email)) throw new ArgumentException("Value cannot be empty or whitespace only string.", "email");

            // Compute MD5 hash
            byte[] hashData;
            using (var md5 = new System.Security.Cryptography.MD5CryptoServiceProvider()) {
                hashData = md5.ComputeHash(Encoding.ASCII.GetBytes(email));
            }

            // Convert it to Base16 string
            var hsb = new StringBuilder(32);
            for (int i = 0; i < hashData.Length; i++) {
                hsb.Append(hashData[i].ToString("x2"));
            }
            return hsb.ToString();
        }

        private static string GetHashForUser(string userName) {
            if (userName == null) throw new ArgumentNullException("userName");
            if (string.IsNullOrWhiteSpace(userName)) throw new ArgumentException("Value cannot be empty or whitespace only string.", "userName");

            using (var dc = new FluffyDbContext()) {
                var email = dc.Users.Where(x => x.UserName.Equals(userName)).Select(x => x.Email).FirstOrDefault();
                if (string.IsNullOrWhiteSpace(email)) return null;
                return ComputeMD5(email.ToLower());
            }
        }
    }
}